﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using iHouse.Common.Configuration;

namespace iHouse.Infrastructure
{
    public class PaginationList<T> : List<T>, IPaginationList
    {
        private readonly int DEFAULT_GROUP_SIZE = IHouseSection.Current.PageGroupSize;

        public PaginationList()
        { }

        public PaginationList(IQueryable<T> source, int pageIndex, int pageSize, string search, params object[] searchValues)
            : this(source, pageIndex, pageSize, 0, search, searchValues)
        { }

        public PaginationList(IQueryable<T> source, int pageIndex, int pageSize, int pageGroupSize, string search, params object[] searchValues)
        {
            if (pageIndex < 0)
                throw new ArgumentOutOfRangeException("index", pageIndex, "PageIndex cannot be below 0.");
            if (pageSize < 1)
                throw new ArgumentOutOfRangeException("pageSize", pageSize, "PageSize cannot be less than 1.");

            if (!string.IsNullOrEmpty(search))
            {
                source = source.Where(search, searchValues);
            }

            PageSize = pageSize;
            PageIndex = pageIndex;
            PageGroupSize = DEFAULT_GROUP_SIZE;
            TotalCount = source.Count();
            TotalPages = TotalCount > 0 ? (int)Math.Ceiling(TotalCount / (double)PageSize) : 0;

            AddRange(source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList());
        }

        public int TotalCount
        {
            get;
            private set;
        }

        public int TotalPages
        {
            get;
            private set;
        }

        public int PageIndex
        {
            get;
            private set;
        }

        public int PageSize
        {
            get;
            private set;
        }

        public bool HasPreviousPage
        {
            get
            {
                return (PageIndex > 1);
            }
        }

        public bool HasNextPage
        {
            get
            {
                return PageIndex < TotalPages;
            }
        }

        public bool IsLastPage
        {
            get
            {
                return PageIndex >= TotalPages;
            }
        }

        public bool IsFirstPage
        {
            get
            {
                return PageIndex <= 1;
            }
        }

        public bool IsFirstGroup
        {
            get
            {
                return PageIndex <= PageGroupSize;
            }
        }

        public bool IsLastGroup
        {
            get
            {
                if (IsLastPage)
                    return true;

                var index = (PageIndex % PageGroupSize) == 0 ? PageIndex / PageGroupSize : (PageIndex / PageGroupSize) + 1;
                return (index * PageGroupSize) + 1 > TotalPages;
            }
        }

        private IList<int> m_Indexs = null;
        public IList<int> IndexGroup
        {
            get
            {
                if (this.m_Indexs == null)
                    m_Indexs = GetPageIndexsByGroup();
                return m_Indexs;
            }
        }

        public string GenericType
        {
            get
            {
                return typeof(T).Name;
            }
        }

        public int PageGroupSize
        {
            get;
            private set;
        }

        #region Private

        private IList<int> GetPageIndexsByGroup()
        {
            List<int> indexs = new List<int>();

            int seed = PageIndex % DEFAULT_GROUP_SIZE;
            int group = (int)PageIndex / DEFAULT_GROUP_SIZE;

            if (seed == 0)
            {
                group--;
            }

            int start = group * DEFAULT_GROUP_SIZE + 1;

            for (int i = 1; i <= DEFAULT_GROUP_SIZE && start <= TotalPages; i++)
            {
                indexs.Add(start);
                start++;
            }

            return indexs;
        }

        #endregion
    }
}